#include <windows.h>
#include <GL/glut.h>
#include <stdlib.h>

GLsizei winWidth = 600, winHeight = 600;
GLfloat xwcMin = 0.0, xwcMax = 225.0;
GLfloat ywcMin = 0.0, ywcMax = 225.0;

typedef struct {
    GLfloat x, y;
} wcPt2D;

typedef GLfloat Matrix3x3[3][3];
Matrix3x3 matComposite;

void init(void) {
    // Set color of display window to white.
    glClearColor(1.0, 1.0, 1.0, 0.0);
}

// Construct the 3x3 identity matrix.
void matrix3x3SetIdentity(Matrix3x3 matIdent) {
    for (int row = 0; row < 3; row++)
        for (int col = 0; col < 3; col++)
            matIdent[row][col] = (row == col) ? 1 : 0;
}

// Premultiply matrix m1 times matrix m2, store result in m2.
void matrix3x3PreMultiply(Matrix3x3 m1, Matrix3x3 m2) {
    Matrix3x3 matTemp;
    for (int row = 0; row < 3; row++)
        for (int col = 0; col < 3; col++)
            matTemp[row][col] = m1[row][0] * m2[0][col] + m1[row][1] * m2[1][col] + m1[row][2] * m2[2][col];
    for (int row = 0; row < 3; row++)
        for (int col = 0; col < 3; col++)
            m2[row][col] = matTemp[row][col];
}

void translate2D(GLfloat tx, GLfloat ty) {
    Matrix3x3 matTransl;
    // Initialize translation matrix to identity.
    matrix3x3SetIdentity(matTransl);
    matTransl[0][2] = tx;
    matTransl[1][2] = ty;
    // Concatenate matTransl with the composite matrix.
    matrix3x3PreMultiply(matTransl, matComposite);
}

// Using the composite matrix, calculate transformed coordinates.
void transformVerts2D(GLint nVerts, wcPt2D* verts) {
    GLfloat temp;
    for (int k = 0; k < nVerts; k++) {
        temp = matComposite[0][0] * verts[k].x + matComposite[0][1] * verts[k].y + matComposite[0][2];
        verts[k].y = matComposite[1][0] * verts[k].x + matComposite[1][1] * verts[k].y + matComposite[1][2];
        verts[k].x = temp;
    }
}

void triangle(wcPt2D verts[]) {
    glBegin(GL_TRIANGLES);
    for (int k = 0; k < 3; k++)
        glVertex2f(verts[k].x, verts[k].y);
    glEnd();
}

void displayFcn(void) {
    // Define initial position for triangle.
    GLint nVerts = 3;
    wcPt2D verts[3] = { {50.0, 25.0}, {150.0, 25.0}, {100.0, 100.0} };

    GLfloat tx = 100.0, ty = 100.0; // Translation amounts

    glClear(GL_COLOR_BUFFER_BIT); // Clear display window.
    glColor3f(0.0, 0.0, 1.0); // Set initial fill color to blue.
    triangle(verts); // Display blue triangle.

    // Initialize composite matrix to identity.
    matrix3x3SetIdentity(matComposite);
    // Apply translation transformation.
    translate2D(tx, ty);

    // Apply composite matrix to triangle vertices.
    transformVerts2D(nVerts, verts);
    glColor3f(1.0, 0.0, 0.0); // Set color for transformed triangle
    triangle(verts); // Display red transformed triangle.
    glFlush();
}

void winReshapeFcn(GLint newWidth, GLint newHeight) {
    glViewport(0, 0, newWidth, newHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(xwcMin, xwcMax, ywcMin, ywcMax);
    glClear(GL_COLOR_BUFFER_BIT);
}

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowPosition(50, 50);
    glutInitWindowSize(winWidth, winHeight);
    glutCreateWindow("Translation with OpenGL");
    init();
    glutDisplayFunc(displayFcn);
    glutReshapeFunc(winReshapeFcn);
    glutMainLoop();
    return 0;
}
